//###############
// FILE : BinaryFileSearch.java
// WRITER : Lior Zimmerman liorz06 066462300
// WRITER : Ohad Dan ohad_dan 036767960
// EXERCISE : oop ex3 2008
// DESCRIPTION: Searching for binary content in a file.
//###############
package oop.ex3.fileSearchModel.SearchEngine;

import java.io.*;
import oop.ex3.fileSearchModel.filters.*;
import oop.ex3.fileSearchModel.filters.Conditionable.STATUS;
import java.util.ArrayList;
import java.util.Iterator;
import oop.ex3.fileSearchModel.util.exceptions.ReaderIOException;

/**
 * Searching for binary content in a file.
 */
public class BinaryFileSearch extends FileSearcher {
	//***********************************************************************
	//  Constants :                                                         *
	//***********************************************************************
	private static final int DATASIZE = 256;	
    //***********************************************************************
	//  Data members :                                                      *
	//***********************************************************************
    private BufferedInputStream _reader;
    private FileInputStream _stream;
    //********************************************************************
	//  Finals :                                                         *
	//********************************************************************
	private final String IO_EXCEPTION_MESSAGE = "Error:I/O failure";
	//***********************************************************************
	//  Methods :                                                           *
	//***********************************************************************
    
    /**
     * Construct a new binary file searcher for the file.
     * @param keywords The list of the filters with bytes to be searched
     * in the file.
     * @throws ReaderIOException in case of I/O error.
     */
    public BinaryFileSearch( ArrayList<Filter> keywords) 
    throws ReaderIOException {
            super(keywords.get(0).getFile());
            _keywords = keywords;
            try { 
                _stream = new FileInputStream(_file);
                _reader = new BufferedInputStream( _stream );   
            }
            catch ( FileNotFoundException e) {
                throw new ReaderIOException(IO_EXCEPTION_MESSAGE);
            }            
    }
    /**
     * Sets the status of byte filters.
     * @return True if there are byte filters left which their
     * content was not found, false otherwise.
     */
    public boolean startSearch() throws IOException {
        byte bytearr[] = new byte[DATASIZE];
        try{
            while( _reader.read(bytearr) != -1) {
                ArrayList<Filter> list = searchInData(bytearr);
                if ( !list.isEmpty() ) {
                    setNodesStatus(list, STATUS.TRUE);
                    _keywords.removeAll(list);
                    return true;
                }
            }
            close();
        }
        catch( IOException e ) {
            throw e;
        }
        //All nodes found in the list after finishing the scan,
        //are not found in the list - so there status should be false.
        setNodesStatus(_keywords, STATUS.FALSE);
        return false;
    }
    /**
     * Search file's data for desired content.
     * @param arr Byte array to look in.
     * @return A list with all files that contains the searched content.
     */
    private ArrayList<Filter> searchInData(byte[] arr) {
        ArrayList<Filter> list = new ArrayList<Filter>();
        Iterator<? extends Filter> it = _keywords.iterator();
        while ( it.hasNext() ){
            Filter item = it.next();
            for ( int i=0; i<arr.length; i++ ) {
                if ( Byte.parseByte(item.getData()) == arr[i] ) {
                    list.add(item);
                    break;
                }
            }
        }
        return list;
    }

    /**
     * Close the stream.
     * @throws IOException In case of error in stream close.
     */
    public void close() throws IOException {
        try {
            _reader.close();
            _stream.close();
        }
        catch( IOException e) {
            throw e;
        }
    }

}
